/**
 * 
 */
package it.unical.canonaco.rende.igpe.game.cbv.guilayer.components;

import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Point;
import java.awt.image.TileObserver;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.imageio.ImageIO;
import javax.swing.plaf.metal.MetalTextFieldUI;

import it.unical.canonaco.rende.igpe.game.cbv.guilayer.guievents.GraphicEventManager;
import it.unical.canonaco.rende.igpe.game.cbv.guilayer.match.UtilityCircle;
import it.unical.canonaco.rende.igpe.game.cbv.guilayer.sprites.LinkedSpriteSheet;
import it.unical.canonaco.rende.igpe.game.cbv.guilayer.sprites.Sprite;
import it.unical.canonaco.rende.igpe.game.cbv.guilayer.sprites.SpriteSheetCache;
import it.unical.canonaco.rende.igpe.game.cbv.guilayer.sprites.UniqueSpriteSheet;
import it.unical.canonaco.rende.igpe.game.cbv.guilayer.sprites.key.ClickOverlayFrameKey;
import it.unical.canonaco.rende.igpe.game.cbv.guilayer.sprites.key.MotionFrameKey;
import it.unical.canonaco.rende.igpe.game.cbv.guilayer.sprites.key.PawnSheetKey;
import it.unical.canonaco.rende.igpe.game.cbv.guilayer.sprites.key.TextureFrameKey;
import it.unical.canonaco.rende.igpe.game.cbv.guilayer.sprites.key.TexturesSheetKey;
import it.unical.canonaco.rende.igpe.game.cbv.logiclayer.engine.actions.AbilityAttackAction;
import it.unical.canonaco.rende.igpe.game.cbv.logiclayer.engine.actions.ActionCoordinateInfo;
import it.unical.canonaco.rende.igpe.game.cbv.logiclayer.engine.component.pawn.GenericPawn;
import it.unical.canonaco.rende.igpe.game.cbv.logiclayer.engine.component.world.Chessboard;
import it.unical.canonaco.rende.igpe.game.cbv.logiclayer.engine.component.world.TextureInfoBean;
import it.unical.canonaco.rende.igpe.game.cbv.logiclayer.engine.events.AttackEvent;
import it.unical.canonaco.rende.igpe.game.cbv.logiclayer.engine.events.EndMatchEvent;
import it.unical.canonaco.rende.igpe.game.cbv.logiclayer.engine.events.EventManager;
import it.unical.canonaco.rende.igpe.game.cbv.logiclayer.engine.events.GenericEvent;
import it.unical.canonaco.rende.igpe.game.cbv.logiclayer.engine.events.InvalidPointSettingEvent;
import it.unical.canonaco.rende.igpe.game.cbv.logiclayer.engine.events.MovementEvent;
import it.unical.canonaco.rende.igpe.game.cbv.logiclayer.engine.events.MultipleAttacksEvent;
import it.unical.canonaco.rende.igpe.game.cbv.logiclayer.engine.events.NoSkillPointEvent;
import it.unical.canonaco.rende.igpe.game.cbv.logiclayer.engine.events.SelectedCharacterEvent;
import it.unical.canonaco.rende.igpe.game.cbv.logiclayer.engine.events.TurnEvent;
import it.unical.canonaco.rende.igpe.game.cbv.logiclayer.engine.exceptions.InvalidFileException;
import it.unical.canonaco.rende.igpe.game.cbv.logiclayer.engine.component.pawn.Character;
/**
 * @author Massimo Canonaco
 *
 */
public class IsometricMatchPainter extends AbstractPainterManager 
{

        Image test;
        
        /** ... : </br>
         * - point.x means width
         * - point.y means height */
        private Point offset;
        
        /** ... : </br>
         * - point.x means width
         * - point.y means height */
        private Point worldCellTiles;
        
        /** ... : </br>
         * - x means width
         * - y means height */
        private Point pawnCellTiles;
        
        /** */
        private int centringPawnValue;
        
        /** */
//      private HashMap<GenericPawn, Sprite> characterAnimationStatus;
        private HashMap<GenericPawn, SpriteInformation> characterAnimationStatus;
        private HashMap<GenericPawn, LinkedList<GenericEvent>> notifiedEvents;
        /** */
        private List<MovementEvent> onMoving;
        private TexturesSheetKey textureSheetKey;
        private TextureFrameKey singleTextureKey;
        
//      private Point selectededPoint;
        private UtilityCircle pawnCircle;
        
        private boolean abilityOn;
        private UtilityCircle abilityCircle;

        private Image test2;

        private Image test3;
        
        
        TexturesSheetKey overlay;
        ClickOverlayFrameKey clickKey;
        public IsometricMatchPainter(SpriteSheetCache cache, String texturePath, String errorImgPath, List<Character> ownOnTheGround, List<Character> enemyOnTheGround, it.unical.canonaco.rende.igpe.game.cbv.logiclayer.engine.component.world.Map map) 
//      public IsometricMatchPainter(SpriteSheetCache cache, String texturePath, String errorImgPath)
        {
                super(cache, texturePath, errorImgPath);

                System.out.println("CREO PAINTER ISO");
                worldCellTiles = new Point();
                pawnCellTiles = new Point();
                offset = new Point();
                
                onMoving = new LinkedList<>();
                characterAnimationStatus = new HashMap<>();
                spritesCache = cache;
                
//              selected = false;
                pawnCircle = null;
                abilityOn = false;
                abilityCircle = new UtilityCircle();
                
                UniqueSpriteSheet mapOverlays = new UniqueSpriteSheet();
                overlay = new TexturesSheetKey();
                overlay.setMapName(map.getName()+"overlay");
                clickKey = new ClickOverlayFrameKey();
                overlay.setFrameKey(clickKey);
                
                clickKey.setKey(ClickOverlayFrameKey.CLICK_OVERLAY);
                Sprite t = null;
                
                t = new Sprite();
                t.setFrameName(clickKey.getKey());
                t.setHeight(64);
                t.setWidth(128);
                t.setTopX(0);
                t.setTopY(0);
                mapOverlays.addFrame(t);
                
                clickKey.setKey(ClickOverlayFrameKey.RADIUS_FIRST_LEVEL);
                t = new Sprite();
                t.setFrameName(clickKey.getKey());
                t.setHeight(64);
                t.setWidth(128);
                t.setTopX(128);
                t.setTopY(0);
                mapOverlays.addFrame(t);
                
                clickKey.setKey(ClickOverlayFrameKey.RADIUS_SECOND_LEVEL);
                t = new Sprite();
                t.setFrameName(clickKey.getKey());
                t.setHeight(64);
                t.setWidth(128);
                t.setTopX(256);
                t.setTopY(0);
                mapOverlays.addFrame(t);
                
                spritesCache.add(overlay, mapOverlays);
//              selectededPoint = new Point();
//              trickyKey = new PawnSheetKey();
//              trickyKey.setWhat(PawnSheetKey.FRAME_TYPE_ANIMATIONS);
//
//              mfk = new MotionFrameKey();
//              mfk.setKey(MotionFrameKey.IDLE+"0");
//              trickyKey.setFrameKey(mfk);
//              trickyKey.setWhen(PawnSheetKey.FRAME_POINT_YOUR_BACK);
                
                Collection<TextureInfoBean> textureCollection = map.getTextures().values();
                textureSheetKey = new TexturesSheetKey();
                textureSheetKey.setMapName(map.getName());
                
                singleTextureKey = new TextureFrameKey();
                textureSheetKey.setFrameKey(singleTextureKey);
                
                
                try 
                {
                        LinkedSpriteSheet lss = new LinkedSpriteSheet();
                        for (TextureInfoBean textureBean : textureCollection) 
                        {
                                singleTextureKey.setTextureID(textureBean.getAcutalKey());
                                Sprite sprite = new Sprite();
                                sprite.setFrameName(String.valueOf(textureBean.getAcutalKey()));
                                lss.addFrame(sprite);
                                lss.setImage(ImageIO.read(new FileInputStream(textureFolder+textureBean.getName()+"."+textureBean.getExtension())));
                        }
                        spritesCache.add(textureSheetKey, lss);
                        notifiedEvents = new HashMap<GenericPawn,LinkedList<GenericEvent>>();
//                      PawnSheetKey ownedKey = new PawnSheetKey();
//                      MotionFrameKey yourMotions = new MotionFrameKey();
//                      ownedKey.setWhat(PawnSheetKey.FRAME_TYPE_ANIMATIONS);
//                      ownedKey.setFrameKey(yourMotions);
//                      yourMotions.setKey(MotionFrameKey.IDLE+"0");
//                      ownedKey.setWhen(PawnSheetKey.FRAME_POINT_YOUR_BACK);
                        SpriteInformation spriteInformation = null;
                        for (Character character : ownOnTheGround) 
                        {
                                PawnSheetKey ownedKey = new PawnSheetKey();
                                MotionFrameKey yourMotions = new MotionFrameKey();
                                ownedKey.setWhat(PawnSheetKey.FRAME_TYPE_ANIMATIONS);
                                ownedKey.setFrameKey(yourMotions);
                                yourMotions.setKey(MotionFrameKey.IDLE+"0");
                                ownedKey.setWhen(PawnSheetKey.FRAME_POINT_YOUR_BACK);
                                
                                System.out.println("tuo: "+character.getName());
                                ownedKey.setWho(character.getType());
//                              trickyKey.setWho(character.getType());
                                spriteInformation = new SpriteInformation();
                                spriteInformation.sprite = spritesCache.getSpriteFrame(ownedKey, true);
                                spriteInformation.spriteKey = ownedKey;
//                              characterAnimationStatus.put(character, spritesCache.getSpriteFrame(trickyKey, true));
                                characterAnimationStatus.put(character, spriteInformation);
                                notifiedEvents.put(character, new LinkedList<GenericEvent>());
                        }

//                      PawnSheetKey enemyKey = new PawnSheetKey();
//                      MotionFrameKey hisMotions = new MotionFrameKey();
//                      enemyKey.setWhat(PawnSheetKey.FRAME_TYPE_ANIMATIONS);
//                      enemyKey.setFrameKey(hisMotions);
//                      hisMotions.setKey(MotionFrameKey.IDLE+"0");
//                      enemyKey.setWhen(PawnSheetKey.FRAME_POINT_ENEMY_FRONT);
                        for (Character character : enemyOnTheGround) 
                        {
                                PawnSheetKey enemyKey = new PawnSheetKey();
                                MotionFrameKey hisMotions = new MotionFrameKey();
                                enemyKey.setWhat(PawnSheetKey.FRAME_TYPE_ANIMATIONS);
                                enemyKey.setFrameKey(hisMotions);
                                hisMotions.setKey(MotionFrameKey.IDLE+"0");
                                enemyKey.setWhen(PawnSheetKey.FRAME_POINT_ENEMY_FRONT);
                                System.out.println("suo: "+character.getName());
//                              trickyKey.setWho(character.getType());
                                enemyKey.setWho(character.getType());
//                              trickyKey.setWhen(PawnSheetKey.FRAME_POINT_ENEMY_FRONT);
                                spriteInformation = new SpriteInformation();
                                spriteInformation.sprite = spritesCache.getSpriteFrame(enemyKey, true);
                                spriteInformation.spriteKey = enemyKey;
//                              characterAnimationStatus.put(character, spritesCache.getSpriteFrame(trickyKey, true));
                                characterAnimationStatus.put(character, spriteInformation);
                                notifiedEvents.put(character, new LinkedList<GenericEvent>());
                                //                      mfk = new MotionFrameKey();
                                //                      mfk.setKey(MotionFrameKey.ATTACK+"3");
                        }
                        
//                      System.out.println(characterAnimationStatus.keySet().size());
                } catch (InvalidFileException | IOException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                }
                try {
//                      test = ImageIO.read(new FileInputStream("testFolder\\mappa\\prototype.png"));
//                      test = ImageIO.read(new FileInputStream("testFolder\\mappa\\isoclick.png"));
//                      test2 = ImageIO.read(new FileInputStream("testFolder\\mappa\\radiuscell.png"));
//                      test3 = ImageIO.read(new FileInputStream("testFolder\\mappa\\radiusabilitycell.png"));
                        mapOverlays.setImage(ImageIO.read(new FileInputStream("cbvapps\\uiresource\\data\\misc\\isometricmapoverlay.png")));

                } catch (FileNotFoundException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                } catch (IOException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                }
        }


	/* (non-Javadoc)
	 * @see it.unical.canonaco.rende.igpe.game.cbv.logiclayer.engine.events.EventListener#notify(it.unical.canonaco.rende.igpe.game.cbv.logiclayer.engine.events.GenericEvent)
	 */
	@Override
	public void notify(GenericEvent event) 
	{
//		try {
			float idEvent = event.getGUID();
			if (idEvent == AttackEvent.GLOBALLY_UNIQUE_IDENTIFIER) 
			{
				AttackEvent attack = (AttackEvent) event;
				LinkedList<GenericEvent> events = notifiedEvents.get(attack.getFrom());
				events.addLast(event);
				
				if(attack.getFrom() != attack.getTo() )
				{
					events = notifiedEvents.get(attack.getTo());
					events.addLast(event);
				}
			}
			else if(idEvent == MultipleAttacksEvent.GUID)
			{
				MultipleAttacksEvent multipleAttacks = (MultipleAttacksEvent)event;
				LinkedList<AttackEvent> attacks = multipleAttacks.getAttacks();
				
				GenericPawn from = attacks.get(0).getFrom();
				notifiedEvents.get(from).addLast(attacks.get(0));
				
				for (AttackEvent attackEvent : attacks) 
				{
					if(attackEvent.getTo() != from)
					{
						notifiedEvents.get(attackEvent.getTo()).addLast(attackEvent);
					}
				}
				
			}
			else if(idEvent == EndMatchEvent.GUID)
			{


                        }
                        else if(idEvent == MovementEvent.GUID)
                        {
                                MovementEvent movement = (MovementEvent)event;
                                LinkedList<GenericEvent> events = notifiedEvents.get(movement.getActor());
//                              System.err.println("from "+movement.getFrowRow()+" "+movement.getFromColumn()+" to "+movement.getActualRow()+" "+movement.getActualColumn());
                                events.addLast(event);
                        }
                        else if(idEvent == NoSkillPointEvent.GUID)
                        {

                        }
                        else if(idEvent == TurnEvent.GUID)
                        {

                        }
                        else if(idEvent == InvalidPointSettingEvent.GUID)
                        {
//                              System.err.println("MIDIDI");
                        }
//                      else if(idEvent == SelectedCharacterEvent.GUID)
//                      {
//                              SelectedCharacterEvent selectedEvent = (SelectedCharacterEvent)event;
//                              selected = true;
//                              pawnCircle = selectedEvent.getCircleInfo();
//                      }
//              } catch (InvalidFileException e) {
//                      // TODO Auto-generated catch block
//                      e.printStackTrace();
//              }
        }

        /* (non-Javadoc)
         * @see it.unical.canonaco.rende.igpe.game.cbv.guilayer.components.AbstractPainterManager#coordinates(int, int, int, java.awt.Point)
         */
        @Override
        public void coordinates(int wildX, int wildY, int tile, Point storage) 
        {
                int x = wildX - offset.x;
                int y = wildY - offset.y;
                int WIDTH_HALF = worldCellTiles.x, HEIGHT_HALF = worldCellTiles.y;
                double Det = (2*WIDTH_HALF*HEIGHT_HALF);
                
                int twoDx =  (int) ((int) (x * HEIGHT_HALF + y * WIDTH_HALF - (WIDTH_HALF*HEIGHT_HALF) )/Det);
                int twoDy = (int) ((int) (x * (-HEIGHT_HALF) + y * WIDTH_HALF + (WIDTH_HALF*HEIGHT_HALF))/Det);
                
//              System.out.println(" hai clickato RIGA: "+ twoDx+ " - COLONNA: "+ twoDy);       
                storage.x = twoDx;
                storage.y = twoDy;
        }

        /* (non-Javadoc)
         * @see it.unical.canonaco.rende.igpe.game.cbv.guilayer.components.AbstractPainterManager#paintClickPoint(int, int, int, float, java.awt.Graphics2D)
         */
        @Override
        public void paintClickPoint(int wildX, int wildY, int tile, float opacity,      Graphics2D graphics) throws InvalidFileException 
        {
                clickKey.setKey(ClickOverlayFrameKey.CLICK_OVERLAY);
                Image click = spritesCache.getImage(overlay, 0, true);
                graphics.drawImage(click, rowFromMapToScreen(wildX, wildY), columnFromMapToScreen(wildX, wildY), null);

//              graphics.drawImage(test, rowFromMapToScreen(wildX, wildY), columnFromMapToScreen(wildX, wildY), null);
        }

        /* (non-Javadoc)
         * @see it.unical.canonaco.rende.igpe.game.cbv.guilayer.components.AbstractPainterManager#paintPawn(it.unical.canonaco.rende.igpe.game.cbv.logiclayer.engine.component.pawn.GenericPawn, int, java.awt.Graphics2D)
         */
        @Override
        public void paintPawn(GenericPawn pawn, int tile, Graphics2D graphics)
                        throws InvalidFileException {
                
                int row = pawn.getRow(), column = pawn.getColumn();
                SpriteInformation information = characterAnimationStatus.get(pawn);
                information.spriteKey.setWho(pawn.getType());
                ((MotionFrameKey)information.spriteKey.getFrameKey()).setKey(information.sprite.getFrameName());
//              trickyKey.setWho(pawn.getType());
//              mfk.setKey(characterAnimationStatus.get(pawn).getFrameName());
//              mfk.setKey(characterAnimationStatus.get(pawn).sprite.getFrameName());

                int isoX = ((row - column) *pawnCellTiles.x) + offset.x,
                        isoY = ((row + column)*worldCellTiles.y - centringPawnValue) + offset.y ;

//              graphics.drawImage(spritesCache.getImage(trickyKey, 0, true), isoX, isoY, null);
                graphics.drawImage(spritesCache.getImage(information.spriteKey, 0, true), isoX, isoY, null);
        }

        @Override
        public void paintPawn(GenericPawn pawn, int wildX, int wildY, int tile, Graphics2D graphics) throws InvalidFileException 
        {
//              mfk.setKey(characterAnimationStatus.get(pawn).getFrameName());
//              mfk.setKey(characterAnimationStatus.get(pawn).sprite.getFrameName());
                SpriteInformation information = characterAnimationStatus.get(pawn);
                information.spriteKey.setWho(pawn.getType());
                ((MotionFrameKey)information.spriteKey.getFrameKey()).setKey(information.sprite.getFrameName());
//              graphics.drawImage(spritesCache.getImage(trickyKey, 0, true), wildX, wildY, null);
                graphics.drawImage(spritesCache.getImage(information.spriteKey, 0, true), wildX, wildY, null);
        }
        
        /* (non-Javadoc)
         * @see it.unical.canonaco.rende.igpe.game.cbv.guilayer.components.AbstractPainterManager#paintColoredCell(int, int, int, float, java.awt.Color, java.awt.Graphics2D)
         */
        @Override
        public void paintColoredCell(int row, int colum, int tile, float opacity, Color color, Graphics2D graphics) throws InvalidFileException 
        {
                // TODO Auto-generated method stub
        }

        /* (non-Javadoc)
         * @see it.unical.canonaco.rende.igpe.game.cbv.guilayer.components.AbstractPainterManager#paintTexturedCell(int, int, int, it.unical.canonaco.rende.igpe.game.cbv.logiclayer.engine.component.world.TextureInfoBean, java.awt.Graphics2D)
         */
        @Override
        public void paintTexturedCell(int row, int column, int tile, TextureInfoBean textureBean, Graphics2D graphics) throws InvalidFileException 
        {
                singleTextureKey.setTextureID(textureBean.getAcutalKey());
                int x = ((row - column) * worldCellTiles.x) + offset.x;
                int y = ((row + column) * worldCellTiles.y) + offset.y;
                graphics.drawImage(spritesCache.getImage(textureSheetKey, 0, true), x, y, null);
        }

        /* (non-Javadoc)
         * @see it.unical.canonaco.rende.igpe.game.cbv.guilayer.components.AbstractPainterManager#paintScene(int, it.unical.canonaco.rende.igpe.game.cbv.logiclayer.engine.component.world.Chessboard, java.awt.Graphics2D)
         */
        @Override
        public void paintScene(int tile, Chessboard board, Graphics2D graphics) throws InvalidFileException {

                graphics.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,1.0f));
                graphics.setFont(OverallGUILayoutFactory.getInstance().getParagraphFont().deriveFont(25.0f));
                graphics.setColor(Color.red);
//              System.out.println("painting scene");
                clickKey.setKey(ClickOverlayFrameKey.RADIUS_FIRST_LEVEL);
                Image click1 = spritesCache.getImage(overlay, 0, true);
                
                clickKey.setKey(ClickOverlayFrameKey.RADIUS_SECOND_LEVEL);
                Image click2 = spritesCache.getImage(overlay, 0, true);
                
                GenericPawn pawnToDraw = null;
                String frameName = null;
                SpriteInformation info = null;
                for(int i = 0; i < board.getSize(); i++)
                        for(int j = 0; j < board.getSize(); j++)
                        {
                                paintTexturedCell(i, j, tile, board.getTexture(i, j), graphics);
                                if(pawnCircle != null && pawnCircle.inside(i, j))
                                {
//                                      System.out.println("paint "+i+" "+j);
                                        int x = ((i - j) * worldCellTiles.x) + offset.x;
                                        int y = ((i + j) * worldCellTiles.y) + offset.y;
                                        graphics.drawImage(click1, x, y, null);
                                        
//                                      graphics.drawImage(test2, x, y, null);
                                }
                                
                                if(abilityOn && abilityCircle.inside(i, j))
                                {
//                                      System.out.println("dipingo "+abilityCircle.getRadius());
                                        int x = ((i - j) * worldCellTiles.x) + offset.x;
                                        int y = ((i + j) * worldCellTiles.y) + offset.y;
                                        graphics.drawImage(click2, x, y, null);
//                                      graphics.drawImage(test3, x, y, null);
                                }
                                
                                pawnToDraw = board.getPawn(i, j);
                                if(pawnToDraw != null)
                                {
                                        info = characterAnimationStatus.get(pawnToDraw);
                                        frameName = characterAnimationStatus.get(pawnToDraw).sprite.getFrameName();
                                        if(!frameName.startsWith(MotionFrameKey.MOVE))
                                                paintPawn(pawnToDraw, 128, graphics);
                                        if(info.damageToShow != 0.0f)
                                        {
                                                if(info.damageToShow > 0.0f)
                                                        graphics.setColor(Color.green);
                                                else
                                                        graphics.setColor(Color.red);
                                                //                                              paintNumber(character.getRow(), character.getColumn(), graphics, characterAnimationStatus.get(character).damageToShow);
                                                paintNumber(pawnToDraw.getRow(), pawnToDraw.getColumn(), graphics, info.damageToShow);
                                        }

                                }
                        }
                
                Set<GenericPawn> pawns = characterAnimationStatus.keySet();
                for (GenericPawn character : pawns) 
                {
                        info = characterAnimationStatus.get(character);
                        frameName = characterAnimationStatus.get(character).sprite.getFrameName();
                        if(frameName.startsWith(MotionFrameKey.DEATH))
                                paintPawn(character, 128, graphics);
                        if(info.damageToShow != 0.0f)
                        {
                                if(info.damageToShow > 0.0f)
                                        graphics.setColor(Color.green);
                                else
                                        graphics.setColor(Color.red);
                                paintNumber(character.getRow(), character.getColumn(), graphics, info.damageToShow);
                        }
                        
                }
//              for (GenericPawn character : characterAnimationStatus.keySet()) 
//              {
//                      info = characterAnimationStatus.get(character);
//                      frameName = characterAnimationStatus.get(character).sprite.getFrameName();
//                      if(!frameName.startsWith(MotionFrameKey.MOVE))
//                              paintPawn(character, 128, graphics);
//                      if(info.damageToShow != 0.0f)
//                      {
//                              if(info.damageToShow > 0.0f)
//                                      graphics.setColor(Color.green);
//                              else
//                                      graphics.setColor(Color.red);
//                              paintNumber(character.getRow(), character.getColumn(), graphics, characterAnimationStatus.get(character).damageToShow);
//                      }
//                      
//              }
                
//              System.out.println("in movimento ci sono "+onMoving.size());
                for (MovementEvent e : onMoving) 
                {
                        paintPawn(e.getActor(), e.getFrowRow(), e.getFromColumn(), 0, graphics);
                }
        }

        /* (non-Javadoc)
         * @see it.unical.canonaco.rende.igpe.game.cbv.guilayer.components.AbstractPainterManager#updateStatus()
         */
        @Override
        public void updateStatus() 
        {
                try 
                {
                        Sprite sprite = null;
                        boolean idleStatus = false;
                        List<GenericEvent> pendingEvents = null;
                        
                        int ofRow, ofColumn, otRow, otColumn;
                        
                        Iterator<MovementEvent> movementIterator = onMoving.iterator();
                        MovementEvent aMovementEvent = null;
                        while(movementIterator.hasNext()) 
                        {
                                aMovementEvent = movementIterator.next(); 
                                ofRow = aMovementEvent.getFrowRow();
                                ofColumn = aMovementEvent.getFromColumn();
                                otRow = aMovementEvent.getActualRow();
                                otColumn = aMovementEvent.getActualColumn();
                                
                                // This event has reached the final points
                                if(ofRow == otRow && ofColumn == otColumn)
                                {
                                        // Drop it
                                        movementIterator.remove();
                                        
                                        // Back the character animation status to idle one
                                        SpriteInformation info = characterAnimationStatus.get(aMovementEvent.getActor());
                                        ((MotionFrameKey)info.spriteKey.getFrameKey()).setKey(MotionFrameKey.IDLE+"0");
                                        info.sprite = spritesCache.getSpriteFrame(info.spriteKey, true);
                                        characterAnimationStatus.put(aMovementEvent.getActor(),info);
                                }
                                // Event must be updated
                                else
                                {
//                                      System.out.println("otRow "+otRow+" ofRow "+ofRow);
                                        // Row updates
                                        if(ofRow < otRow)
                                        {
//                                              aMovementEvent.setFrowRow(ofRow+1);
                                                aMovementEvent.setFrowRow(ofRow+4);

                                        }
                                        else if(ofRow > otRow)
                                        {
//                                              aMovementEvent.setFrowRow(ofRow-1);
                                                aMovementEvent.setFrowRow(ofRow-4);

                                        }
                                        
                                        // Column updates
                                        SpriteInformation siInfo = characterAnimationStatus.get(aMovementEvent.getActor());
                                        if(ofColumn < otColumn)
                                        {
                                                aMovementEvent.setFromColumn(ofColumn+4);
                                                switchView(siInfo, false);
                                        }
                                        else if(ofColumn > otColumn)
                                        {
                                                aMovementEvent.setFromColumn(ofColumn-4);
                                                switchView(siInfo, true);
                                        }
                                        siInfo.sprite = spritesCache.getSpriteFrame(siInfo.spriteKey, true);
                                }
                        }
                        
                        SpriteInformation information = null;
                        Iterator<GenericPawn> iteratorPawnsToDraw = characterAnimationStatus.keySet().iterator();
                        GenericPawn subject = null;
//                      for (GenericPawn subject : pawnsToDraw)
                        while(iteratorPawnsToDraw.hasNext())
                        {
                                subject = iteratorPawnsToDraw.next();
//                              sprite = characterAnimationStatus.get(subject);
                                information = characterAnimationStatus.get(subject);
                                sprite = characterAnimationStatus.get(subject).sprite;
                                pendingEvents = notifiedEvents.get(subject);
                                idleStatus = sprite.getFrameName().startsWith(MotionFrameKey.IDLE);
                                
                                // If the subject is IDLEing, and there's at least one pending event.
                                if(idleStatus && !pendingEvents.isEmpty())
                                {
                                        // Get the first pending event
                                        GenericEvent firstPending = pendingEvents.remove(0);

                                        // Get event id
                                        float pendingGUID = firstPending.getGUID();

                                        // If it's attack
                                        if(pendingGUID == AttackEvent.GLOBALLY_UNIQUE_IDENTIFIER)
                                        {
                                                AttackEvent attack = (AttackEvent) firstPending;

						// If subject attacks
						if(subject == attack.getFrom())
						{
							// Switch to the attack animation
							((MotionFrameKey)information.spriteKey.getFrameKey()).setKey(MotionFrameKey.ATTACK+"0");
							
							// If it's a self cast spell
							if(subject == attack.getTo())
							{
								information.damageToShow = attack.getTotalDamage();
							}
						}
						// else if subject is damaged
						else
						if(subject == attack.getTo())
						{
							float damage = attack.getTotalDamage();
							if(!attack.isFriendly())
							{
								damage = -damage;
							}
							
							if(damage <= 0)
							{
								// If successfull is true, our subject is not dead
								if(attack.isSuccessfull())
								{
									// Switch to the damaged animation
									//								mfk.setKey(MotionFrameKey.DAMAGED+"0");
									((MotionFrameKey)information.spriteKey.getFrameKey()).setKey(MotionFrameKey.DAMAGED+"0");
								}
								else
								{
									// Switch to the death animation
									//								mfk.setKey(MotionFrameKey.DEATH+"0");
									((MotionFrameKey)information.spriteKey.getFrameKey()).setKey(MotionFrameKey.DEATH+"0");
								}
							}
							information.damageToShow = damage;
						}
					}
					// else if it's movement
					else if(pendingGUID == MovementEvent.GUID)
					{
						MovementEvent movement = (MovementEvent) firstPending;


                                                // Switch to the walk animation
//                                              mfk.setKey(MotionFrameKey.MOVE+"0");
                                                ((MotionFrameKey)information.spriteKey.getFrameKey()).setKey(MotionFrameKey.MOVE+"0");
                                                
                                                // Convert the coordinate values from "map system" to "screen system"
                                                int originalFromRow = movement.getFrowRow(), 
                                                                originalFromColumn = movement.getFromColumn(),
                                                                originalToRow = movement.getActualRow(),
                                                                originalToColumn = movement.getActualColumn();
                                                movement.setFrowRow(this.pRowFromMapToScreen(originalFromRow, originalFromColumn));
                                                movement.setFromColumn(this.pColumnFromMapToScreen(originalFromRow, originalFromColumn));
                                                movement.setActualRow(this.pRowFromMapToScreen(originalToRow, originalToColumn));
                                                movement.setActualColumn(this.pColumnFromMapToScreen(originalToRow, originalToColumn));
                                                
                                                // Save movement informations, with his new values, into the onMoving list
                                                onMoving.add(0, movement);
                                        }

//                                      sprite = spritesCache.getSpriteFrame(trickyKey, true);
                                        sprite = spritesCache.getSpriteFrame(information.spriteKey, true);
                                }
                                // Subject is not IDLEing or there's a previous "event animation" for him
                                else
                                {
                                        // If Animation is not over
                                        if(sprite.getNext() != null)
                                        {
                                                sprite = information.sprite.getNext();
//                                              sprite = sprite.getNext();
                                        }
                                        // Animation is over, back to the appropriate first one
                                        else
                                        {
//                                              System.out.println("ANIMATION OVER");
                                                // Character is moving, so back to the fist move animation
                                                if(sprite.getFrameName().startsWith(MotionFrameKey.MOVE))
                                                {
//                                                      mfk.setKey(MotionFrameKey.MOVE+"0");
                                                        ((MotionFrameKey)information.spriteKey.getFrameKey()).setKey(MotionFrameKey.MOVE+"0");
                                                        
                                                }
                                                // Character is not moving and he's not dead, so back to the first idle animation
                                                else if(!sprite.getFrameName().startsWith(MotionFrameKey.DEATH))
                                                {
//                                                      mfk.setKey(MotionFrameKey.IDLE+"0");
                                                        ((MotionFrameKey)information.spriteKey.getFrameKey()).setKey(MotionFrameKey.IDLE+"0");
                                                        information.damageToShow = 0.0f;
                                                }
                                                // Character is dead and the death animation is over
                                                else
                                                {
//                                                      characterAnimationStatus.remove(subject);
                                                        iteratorPawnsToDraw.remove();
                                                }


//						sprite = spritesCache.getSpriteFrame(trickyKey, true);
						sprite = spritesCache.getSpriteFrame(information.spriteKey, true);
					}
				}
				
				// There's the appropriate sprite now, set it to the character
				information.sprite = sprite;
//				characterAnimationStatus.put(subject, sprite);
			}
			} catch (InvalidFileException e) 
			{
				// It's not possible, because the animations files are loaded into constructor :trollface:.
			}
	}
	
	@Override
	public void setting(EventManager eventManager) 
	{
		super.setting(eventManager);
		
		eventManager.addListener(this, new AttackEvent(false, false, null, null, null, 0.0f));
		eventManager.addListener(this, new EndMatchEvent(null, null));
		eventManager.addListener(this, new MovementEvent(null, 0, 0, 0, 0));
		eventManager.addListener(this, new NoSkillPointEvent(null, null));
		eventManager.addListener(this, new TurnEvent());
		eventManager.addListener(this, new MultipleAttacksEvent(0,0));
	}
	/** */
	public void settingUp(int widthTilePawn, int heightTilePawn, int widthTileWorld, int heightTileWorld, int offsetWidth, int offsetHeight)
	{
		pawnCellTiles.x = widthTilePawn/2;
		pawnCellTiles.y = heightTilePawn/2;
		
		worldCellTiles.x = widthTileWorld/2;
		worldCellTiles.y = heightTileWorld/2;
		this.offset.x = offsetWidth;
		this.offset.y = offsetHeight;
		
		centringPawnValue = (pawnCellTiles.y + worldCellTiles.y - worldCellTiles.y/2);
	}
	
	/** */
	public void paintNumber(int wildX, int wildY, Graphics2D graphics, float toPaint)
	{
//		System.out.println("paint damage "+toPaint);
		int x = pRowFromMapToScreen(wildX, wildY), y = pColumnFromMapToScreen(wildX,wildY);
		graphics.drawString(Integer.toString((int)toPaint), x, y);
	}
	/** */
	private int rowFromMapToScreen(int row, int column)
	{
		return ((row - column) *worldCellTiles.x) + offset.x;
	}
	
	/** */
	private int columnFromMapToScreen(int row, int column)
	{
		return ((row + column)*worldCellTiles.y) + offset.y;
	}
	
	/** */
	private int pRowFromMapToScreen(int row, int column)
	{
		/*
		 * int isoX = ((row - column) *pawnCellTiles.x) + offset.x,
			isoY = ((row + column)*worldCellTiles.y - centringPawnValue) + offset.y ;
		 */
		return ((row - column) *pawnCellTiles.x) + offset.x;
	}
	
	/** */
	private int pColumnFromMapToScreen(int row, int column)
	{
		return ((row + column)*worldCellTiles.y - centringPawnValue) + offset.y;
	}
	
	
	private class SpriteInformation
	{
		private Sprite sprite;
		private PawnSheetKey spriteKey;
		private float damageToShow;
	}


//      public void setSourceCirclePoint(int row, int column) 
//      {
//              // TODO Auto-generated method stub
//      }

        public void setSourceCirclePoint(UtilityCircle circleInfo) 
        {
                pawnCircle = circleInfo;
        }
        
        /** */
        public void setAbility(boolean on)
        {
                abilityOn = on;
        }

        /**
         * @return the abilityCircle
         */
        public UtilityCircle getAbilityCircle() {
                return abilityCircle;
        }
        
        /**
         * @throws InvalidFileException  */
        private void switchView(SpriteInformation spriteInformation, boolean up) throws InvalidFileException
        {
                if(up)
                {
                        if(spriteInformation.spriteKey.getWhen() == PawnSheetKey.FRAME_POINT_ENEMY_FRONT)
                        {
                                spriteInformation.spriteKey.setWhen(PawnSheetKey.FRAME_POINT_ENEMY_BACK);
//                      characterAnimationStatus.get(aMovementEvent.getActor()).sprite = spritesCache.getSpriteFrame(characterAnimationStatus.get(aMovementEvent.getActor()).spriteKey, true);
                        }
                        else if(spriteInformation.spriteKey.getWhen() == PawnSheetKey.FRAME_POINT_YOUR_FRONT)
                        {
                                spriteInformation.spriteKey.setWhen(PawnSheetKey.FRAME_POINT_YOUR_BACK);
//                      characterAnimationStatus.get(aMovementEvent.getActor()).sprite = spritesCache.getSpriteFrame(characterAnimationStatus.get(aMovementEvent.getActor()).spriteKey, true);
                        }
                        
                }
                else
                {
                if(spriteInformation.spriteKey.getWhen() == PawnSheetKey.FRAME_POINT_ENEMY_BACK)
                {
                        spriteInformation.spriteKey.setWhen(PawnSheetKey.FRAME_POINT_ENEMY_FRONT);
//                      characterAnimationStatus.get(aMovementEvent.getActor()).sprite = spritesCache.getSpriteFrame(characterAnimationStatus.get(aMovementEvent.getActor()).spriteKey, true);
                }
                else if(spriteInformation.spriteKey.getWhen() == PawnSheetKey.FRAME_POINT_YOUR_BACK)
                {
                        spriteInformation.spriteKey.setWhen(PawnSheetKey.FRAME_POINT_YOUR_FRONT);
//                      characterAnimationStatus.get(aMovementEvent.getActor()).sprite = spritesCache.getSpriteFrame(characterAnimationStatus.get(aMovementEvent.getActor()).spriteKey, true);
                }
                }
                
//              spriteInformation.sprite = spritesCache.getSpriteFrame(spriteInformation.spriteKey, true);
        }

        public boolean didAll() {
                Iterator<GenericPawn> iterator = characterAnimationStatus.keySet().iterator();
                GenericPawn pawn = null;
                while(iterator.hasNext())
                {
                        pawn = iterator.next();
                        if(!characterAnimationStatus.get(pawn).spriteKey.getFrameKey().getKey().startsWith(MotionFrameKey.IDLE) && notifiedEvents.get(pawn).isEmpty())
                        {
//                              System.out.println("pawn "+pawn.getName()+" "+characterAnimationStatus.get(pawn).spriteKey.getFrameKey().getKey());
                                return false;
                        }
                }
                return true;
        }

	@Override
	public void dispose() 
	{
		super.dispose();
		EventManager eventManager = EventManager.getInstance();
		eventManager.removeListener(this, new AttackEvent(false, false, null, null, null, 0.0f));
		eventManager.removeListener(this, new EndMatchEvent(null, null));
		eventManager.removeListener(this, new MovementEvent(null, 0, 0, 0, 0));
		eventManager.removeListener(this, new NoSkillPointEvent(null, null));
		eventManager.removeListener(this, new TurnEvent());
		eventManager.removeListener(this, new MultipleAttacksEvent(0,0));
	}
}

